Shell学习笔记17-Linux信号及trap命令的企业应用

GO


1. 信号知识

1.1. 信号介绍

运行Shell脚本程序时,如果按下快捷键Ctrl+CCtrl+x(x为其它字符),程序就会立刻终止运行。

在有些情况下,我们并不希望Shell脚本在运行时被信号中断,此时就可以使用屏蔽信号手段,让程序忽略用户输入的信号指令,从而继续运行Shell脚本程序。

简单地说,Linux的信号是由一个整数构成的异步消息,它可以由某个进程发给其它的进程,也可以在用户按下特定键发生某种异常事件时,由系统发给某个进程。

1.2. 信号列表

在Linux下和信号相关的常见命令为killtrap,这篇学习笔记重点记录了如何使用trap命令,以及如何利用trap控制的跳板机脚本来使用信号。

执行kill -ltrap -l命令,可以列出系统支持的各种信号,多达64个,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@theshu ~]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX

下面将对企业实战中Linux系统的重要信号进行说明,见下表(在使用信号名时需要省略SIG前缀):

信号 说明
HUP(1) 挂起,通常因终端掉线或用户退出而引发
INT(2) 中断,通常因按下Ctrl+C组合键而引发
QUIT(3) 退出,通常因按下Ctrl+\组合键而引发
ABRT(6) 中止,通常因某些严重的执行错误而引发
ALRM(14) 报警,通常用来处理超时
TERM(15) 终止,通常在系统关机时发送
TSTP(20) 停止进程的运行,但该信号可以被处理和忽略,通常因按下Ctrl+z组合键而引发

通常需要忽略的信号包括HUP、INT、QUIT、TSTP、TERM等,对应的信号编号分别为1、2、3、20、15。Shell脚本中既可以用数字来代表信号,也可以使用信号的名字来代表信号。

2. 使用trap控制信号

trap命令用于指定在接收到信号后将要采取的行动。trap命令的一种常见用途是在脚本程序被中断时完成清理工作,或者屏蔽用户非法使用的某些信号。在使用信号名时需要省略SIG前缀。可以在命令提示符下输入命令trap -l来查看信号的编号及其关联的名称。

trap命令的参数分为两部分,前一部分是接收到指定信号时将要采取的行动,后一部分是要处理的信号名。

trap命令的使用语法如下:trap command signal

  • signal是指接收到的信号
  • command是指接收到该信号应采取的行动
  • 也就是trap '命令; 命令' 信号编号trap '命令; 命令' 信号名

范例1:测试trap命令捕获Ctrl+C信号

1
2
3
4
5
6
7
8
9
[root@theshu ~]# trap 'echo theshu' 2
[root@theshu ~]# ^Ctheshu #<==当执行上述命令后按Ctrl+C键会显示这个
[root@theshu ~]# ^Ctheshu #<==再按Ctrl+C键还会显示
[root@theshu ~]# trap 'echo OK!' INT #<==不用数字信号用信号名也可以
[root@theshu ~]# ^COK!
[root@theshu ~]# ^COK!

stty -a可以列出中断信号与键盘的对应信息,如下:

1
2
3
4
5
6
7
8
9
10
11
[root@theshu ~]# stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke

范例2:测试按下Ctrl+C组合键而引发的INT(2)信号:

1
2
3
4
5
6
7
8
9
[root@theshu ~]# trap "" 2 #<==执行动作处为空,此命令可以用来屏蔽与数字对应的Ctrl+C信号。
[root@theshu ~]# #<==此时执行Ctrl+C键无任何反应
[root@theshu ~]# trap ":" 2 #<==恢复Ctrl+C信号
[root@theshu ~]# ^C #<==此时可以执行Ctrl+C了
[root@theshu ~]# trap "echo -n 'you are typing ctrl+c'" 2
[root@theshu ~]# ^Cyou are typing ctrl+c
[root@theshu ~]# ^Cyou are typing ctrl+c
[root@theshu ~]# ^Cyou are typing ctrl+c
[root@theshu ~]# ^Cyou are typing ctrl+c

范例3:同时处理多个信号

  • 执行任何一个对应信号的事件时,都会执行前面对用的动作,因为动作为空吗,所以执行后没有任何反应。
  • trap "" 1 2 3 20 15 执行这些数字信号,什么都不做
  • trap ":" 1 2 3 20 15 执行这些数字信号,恢复对应功能
  • trap "" HUP INT QUIT TSTP TERM 执行这些名称信号,什么都不做
  • trap ":" HUP INT QUIT TSTP TERM 执行这些名称信号,恢复对应功能
  • 屏蔽1-64的所有数字信号:
    1
    trap "" `echo {1..64}`

3. Linux信号及trap命令的生产应用案例

范例:开发脚本实现触发信号后清理文件功能

  • 脚本如下;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/bin/bash
    trap "find /tmp -type f -name 'theshu_*' | xargs rm -f && exit" INT
    #<==捕获Ctrl+C键后即执行find删除命令
    while true
    do
    touch /tmp/theshu_$(date +%F-%H-%M-%S) #<==在/tmp下创建文件
    sleep 3 #<==休息3秒
    ls -l /tmp/theshu* #<==查看文件创建的情况
    done
  • 执行结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@theshu ~]# sh trap.sh
    -rw-r--r-- 1 root root 0 Mar 2 10:45 /tmp/theshu_2018-03-02-10-45-52
    -rw-r--r-- 1 root root 0 Mar 2 10:45 /tmp/theshu_2018-03-02-10-45-52
    -rw-r--r-- 1 root root 0 Mar 2 10:45 /tmp/theshu_2018-03-02-10-45-55
    -rw-r--r-- 1 root root 0 Mar 2 10:45 /tmp/theshu_2018-03-02-10-45-52
    -rw-r--r-- 1 root root 0 Mar 2 10:45 /tmp/theshu_2018-03-02-10-45-55
    -rw-r--r-- 1 root root 0 Mar 2 10:45 /tmp/theshu_2018-03-02-10-45-58
    ^C[root@theshu ~]# ls /tmp/theshu*
    ls: cannot access /tmp/theshu*: No such file or directory

OK

0%